//------------------------------------------------------------------------------ 
//  <copyright file="ControllerClientMessageHandler.h" company="Microsoft Corporation">
// The MIT License (MIT)
// 
// Copyright (c) 2014, Microsoft Corporation
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//  </copyright>
//------------------------------------------------------------------------------	

#pragma once

#include "stdafx.h"
#include "SharedBufferParameters.h"
#include "KukaLBR4PlusControllerExports.h"
#include "MessageDescription.h"
#include "KukaLBR4ControllerCommon.h"
#include <ControllerStateMachineRegisters.h>

using namespace KukaLBR4ControllerCommonNS;

/// <summary>
/// Used by upstream client to communicate with controller thread.
/// A pointer to a <c>ControllerClientMessageHandler</c> object is returned
/// by <c>KukaLBR4PlusController::StartKukaLBR4PlusController</c> which can then be utilized
/// by the caller (the upstream client or an intermediate layer) to interact with the 
/// controller thread managing the controller state machine and feedback/control of the LBR.
/// </summary>
class KUKALBR4PLUSCONTROLLER_DLLEXPORTIMPORT ControllerClientMessageHandler
{
public :
	/// <summary> Initializes an instance of the <c>ControllerClientMessageHandler class </summary>
	/// <param name="pSbParams">
	/// Shared buffer information necessary for synchronization
	/// with controller thread.
	/// </param>
	ControllerClientMessageHandler(SharedBufferParameters *pSbParams);

	/// <summary> dtor to ensure that quit signal has been sent to controller thread </summary>
	~ControllerClientMessageHandler();

	/// <summary>
	/// Process a single message from a client connection.  Not thread-safe or reentrant.
	/// Response is placed at location indicated by <c>response</c>.  <c>Response</c> must
	/// be pre-allocated.
	/// <param name="pMessage"> Pointer to message to be processed. </param>
	/// <param name="pResponse"> Location to place response.  Must be allocated by caller. </param>
	virtual void ProcessMessage(MessageDescription *pMessage, MessageDescription *pResponse);

private:

	// A buffer for working register values being sent from upstream client to controller
	// state machine.
	// The "working registers" are registers that can be both read and written by the
	// controller state machine, and include the registers that will determine the control
	// parameters for each iteration of the active control executed on the hardware.
	// The working registers can be replaced (all registers must be replaced) by the
	// upstream client via the appropriate message type.
	ControllerStateMachineRegisters<double> *pWorkingRegisters;

	// A buffer for all working and feedback register values being sent from controller
	// state machine to upstream client.
	// the "all registers" contain both the working registers described above, plus
	// additional feedback registers representing the state of the hw.  The additional 
	// feedback registers can only be changed in response to feedback received from the 
	// hw.  The combination of all registers is used for the feedback to the
	// upstream client, so that it can inspect both the state of the controller state machine
	// and the arm itself.
	// the "working copy" is the copy currently being used in the loop, and the "exchange"
	// copy points to the location used for pointer exchange with the controller thread.
	ControllerStateMachineRegisters<double> *pAllRegisters;

	// a register to hold the current controller state machine description
	ControllerStateMachineRegisters<byte> *pCsmdRegister;

	// exchange objects used for synchornizing data with controller thread
	RegisterExchange<double> *pWorkingRegistersExchange;
	RegisterExchange<double> *pAllRegistersExchange;
	RegisterExchange<byte> *pCsmdExchange;

	// Signals indicating state change or when an event occurs that
	// the thread needs to respond to (such as the other thread quitting).
	unsigned volatile int *pQuitSignal;
	unsigned volatile int *pCsmdStatusSignal;
	unsigned volatile int *pNewCsmdReadySignal;

	// ensure we don't send uninitialized feedback to the upstream client
	bool haveValidFeedback;

	// ensure we don't try to run a state machine before it has been initialized by the upstream client
	bool csmdInitialized;

	/// <summary>
	/// Replaces the current set of working registers in the controller state machine with a new 
	/// set of values contained in a message from the upstream client.
	/// </summary>
	/// <param name="pMessage"> Message containing the new working register values. </param>
	void SetNewWorkingRegistersFromMessage(MessageDescription *pMessage);

	/// <summary>
	/// Replaces the current state machine defintion for the controller state machine.
	/// </summary>
	/// <param name="pMessage"> Message containing the new controller state machine description. </param>
	void SetCsmd(MessageDescription *pMessage);

	/// <summary> Build a standard response message to a request from the upstream client. </summary>
	/// <param name="messageType"> Type of message to respond to. </param>
	/// <param name="sequenceNumber"> Sequence number of the message to respond to. </param>
	/// <param name="successful"> Indicates whether or not the the response should indicate success. </param>
	/// <param name="pResponse"> Pointer to a preallocated response message. </param>
	void BuildDefaultMessageResponse(
		MessageTypes messageType,
		unsigned int sequenceNumber,
		bool successful,
		MessageDescription *pResponse);

	/// <summary> Build a feedback response message for the upstream client. </summary>
	/// <param name="sequenceNumber"> Sequence number of the message to respond to. </param>
	/// <param name="successful"> Indicates whether or not the the response should indicate success. </param>
	/// <param name="pResponse"> Pointer to a preallocated response message. </param>
	void BuildFeedbackMessageResponse(
		unsigned int sequenceNumber,
		bool successful,
		MessageDescription *pResponse);
};
